#include "mystdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

#define FILE_MODE 0666

_FILE * _fopen(const char*filename, const char *flag)
{
    assert(filename);
    assert(flag);

    int f = 0, fd = -1;
    if(strcmp(flag, "w") == 0)
    {
        f = (O_CREAT|O_WRONLY|O_TRUNC);
        fd = open(filename, f, FILE_MODE);
    }
    else if(strcmp(flag, "a") == 0) 
    {
        f = (O_CREAT|O_WRONLY|O_APPEND);
        fd = open(filename, f, FILE_MODE);
    }
    else if(strcmp(flag, "r") == 0) 
    {
        f = O_RDONLY;
        fd = open(filename, f);
    }
    else return NULL;

    if(fd == -1) return NULL;

    _FILE *fp = (_FILE*)malloc(sizeof(_FILE));
    if(fp == NULL) return NULL;

    fp->fileno = fd;
    fp->outPos = 0;

    return fp;
}

int _fwrite(_FILE *fp, const char *s, int length)
{
    memcpy(&fp->outBuffer[fp->outPos], s, length); 
    fp->outPos += length;
    
    if(fp->fileno == 1 || fp->fileno == 2)
        fp->flag = FLUSH_LINE;
    else 
        fp->flag = FLUSH_ALL;

    if(fp->flag&FLUSH_NOW)
    {
        write(fp->fileno, fp->outBuffer, fp->outPos);
        fp->outPos = fp->cur = 0;
    }
    else if(fp->flag&FLUSH_LINE)
    {
        int last = -1, i = 0;
        for(; i <= length; ++i)
        {
            // 0 1 2 3 4 5  6 7 8 9 10 11 12 
            // a b c d e \n a b c d e \n  a
            if(fp->outBuffer[i] == '\n')
            {
                write(fp->fileno, fp->outBuffer + last + 1, i - last);
                last = fp->cur = i;
            }
        }
        if(fp->cur == fp->outPos) fp->outPos = fp->cur = 0;
    }
    else if(fp->flag & FLUSH_ALL)
    {
        if(fp->outPos == SIZE)
        {
            write(fp->fileno, fp->outBuffer, fp->outPos);
            fp->outPos = fp->cur = 0;
        }
    }

    return fp->cur + 1;
}

void _fflush(_FILE *fp)
{
    if(fp->outPos > 0 && fp->cur < fp->outPos)
    {
        if(fp->cur == 0) 
            write(fp->fileno, fp->outBuffer, fp->outPos);
        else 
             write(fp->fileno, fp->outBuffer + fp->cur + 1, fp->outPos - fp->cur);
        fp->outPos = 0;
    }
}

void _fclose(_FILE *fp)
{
    if(fp == NULL) return;
    _fflush(fp);
    close(fp->fileno);
    free(fp);
}
